#define _POSIX_SOURCE
#define _BSD_SOURCE

#include "dominion.h"
#include "dominion_helpers.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include "rngs.h"
#include <getopt.h>

#ifndef TEST_CASES
#define TEST_CASES 10000
#endif

#ifndef RAND_NUM
#define RAND_NUM 100
#endif

#ifndef SUPP
#define SUPP 10
#endif

int resetScores(int *players)
{
	int i;

	for (i = 0; i < MAX_PLAYERS; i++) {
		players[i] = 0;
	}

	return 0;
}

int updateScore(int card, int *players, int currentPlayer)
{
	switch (card) {

	case curse:
		players[currentPlayer] -= 1;
		break;
	
	case estate:
		players[currentPlayer] += 1;
		break;

	case duchy:
		players[currentPlayer] += 3;
		break;

	case province:
		players[currentPlayer] += 6;
		break;

	case great_hall:
		players[currentPlayer] += 1;
		break;

	default:
		break;
	}

	return 0;
}

int createGameState(struct gameState *state, int *players)
{
	int i, j;
	int highest;
	int fullDeckCount;
	int num_gardens[MAX_PLAYERS];

	for (i = 0; i < MAX_PLAYERS; i++) {
		num_gardens[i] = 0;
	}

	// Generate 2-4 players
	state->numPlayers = floor(Random() * (MAX_PLAYERS - 1)) + 2;
	state->whoseTurn = floor(Random() * state->numPlayers);

	for (i = MAX_PLAYERS - 1; i >= state->numPlayers; i--) {
		players[i] = -9999;
	}

	for (i = 0; i < state->numPlayers; i++) {
		state->handCount[i] = floor(Random() * RAND_NUM);
		state->deckCount[i] = floor(Random() * RAND_NUM);
		state->discardCount[i] = floor(Random() * RAND_NUM);

		for (j = 0; j < state->handCount[i]; j++) {
			state->hand[i][j] = floor(Random() * (treasure_map + 1));

			if (state->hand[i][j] == gardens) {
				num_gardens[i] += 1;
			} else {
				updateScore(state->hand[i][j], players, i);
			}
		}

		for (j = 0; j < state->deckCount[i]; j++) {
			state->deck[i][j] = floor(Random() * (treasure_map + 1));
			
			if (state->deck[i][j] == gardens) {
				num_gardens[i] += 1;
			} else {
				updateScore(state->deck[i][j], players, i);
			}
		}

		for (j = 0; j < state->discardCount[i]; j++) {
			state->discard[i][j] = floor(Random() * (treasure_map + 1));
			
			if (state->discard[i][j] == gardens) {
				num_gardens[i] += 1;
			} else {
				updateScore(state->discard[i][j], players, i);
			}
		}
	}

	// Update Score for number of gardens & less turns
	for (i = 0; i < state->numPlayers; i++) {
		
		fullDeckCount = state->handCount[i] + state->deckCount[i] + state->discardCount[i];
		players[i] += (fullDeckCount / 10) * num_gardens[i];
	}

	// Get Highest Score for now
	highest = players[0];
	for (i = 1; i < MAX_PLAYERS; i++) {
		if (players[i] > highest) {
			highest = players[i];
		}
	}

	// Add 1 to player with less turns in case of tie
	for (i = 1; i < MAX_PLAYERS; i++) {
		if (players[i] == highest && i > state->whoseTurn) {
			players[i] += 1;
		}
	}

	// Find the updated highest score
	highest = players[0];
	for (i = 1; i < MAX_PLAYERS; i++) {
		if (players[i] > highest) {
			highest = players[i];
		}
	}

	// Set the winners to 1 and the rest to 0
	printf("Score: ");
	for (i = 0; i < MAX_PLAYERS; i++) {

		printf("%d -> %d; ", i, players[i]);
		if (players[i] == highest) {
			players[i] = 1;
		} else {
			players[i] = 0;
		}
	}
	printf("\n");


	return 0;
}

int test(struct gameState *state, int *players)
{
	int i;
	int test_players[MAX_PLAYERS];
	
	for (i = 0; i < MAX_PLAYERS; i++) {
		test_players[i] = 0;
	}

	getWinners(test_players, state);

	printf("Expect \t[%d", players[0]);
	for (i = 1; i < MAX_PLAYERS; i++) {
		printf(", %d", players[i]);
	}
	printf("]\n");

	printf("Actual \t[%d", test_players[0]);
	for (i = 1; i < MAX_PLAYERS; i++) {
		printf(", %d", test_players[i]);
	}
	printf("]\n");

	for (i = 0; i < MAX_PLAYERS; i++) {
		if (players[i] != test_players[i]) {
			return -1;
		}
	}

	return 0;
}

int main(int argc, char **argv)
{
	int i, result;
	int *players;
	struct gameState state;

	players = (int *) malloc(sizeof(int) * MAX_PLAYERS);

	for (i = 0; i < TEST_CASES; i++) {
		resetScores(players);
		createGameState(&state, players);
		result = test(&state, players);
		if (result == 0) {
			printf("TEST CASE #%d = PASS\n", i + 1);
		} else {
			printf("TEST CASE #%d = FAIL <------\n", i + 1);
		}
	}

	return 0;
}